package controller

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"main/model"
	"main/param"
	"main/service"
	"main/tool"
	"os"
	"strconv"
	"strings"
	"time"
)

type MemberController struct {
}

func (mc *MemberController) Router(engine *gin.Engine) {
	engine.GET("/api/sendcode", mc.sendSmsCode)
	engine.POST("/api/login_sms", mc.smsLogin)

	// 生成验证码
	engine.GET("api/captcha", mc.captcha)
	// 验证验证码
	engine.POST("/api/verify_captcha", mc.verifyCaptcha)

	// 用户名+密码+验证码 登录
	engine.POST("/api/login_pwd", mc.nameLogin)

	// 头像上传
	engine.POST("/api/upload/avatar", mc.uploadAvatar)

	// 用户信息查询
	engine.POST("/api/userinfo", mc.userinfo)
}

func (mc *MemberController) userinfo(ctx *gin.Context) {
	cookie, err := tool.CookieAuth(ctx)
	if err != nil {
		tool.Failed(ctx, "还未登录,请先登录")
		ctx.Abort()
		return
	}

	userId := cookie.Value
	ms := &service.MemberService{}
	member := ms.GetUserInfo(userId)
	if member == nil {
		tool.Failed(ctx, "获取用户信息失败")
		return
	}
	tool.Success(ctx, gin.H{
		// 自定义需要的字段返回
		"id":            member.Id,
		"user_name":     member.UserName,
		"mobile":        member.Mobile,
		"register_time": member.RegisterTime,
		"avatar":        member.Avatar,
		"balance":       member.Balance,
		"is_active":     member.IsActive,
		"city":          member.City,
	})
}

// 头像上传
func (mc *MemberController) uploadAvatar(ctx *gin.Context) {
	// 1. 解析参数: avatar, user_id
	userId := ctx.PostForm("user_id")
	fileHeader, err := ctx.FormFile("avatar")
	if err != nil {
		tool.Failed(ctx, "参数解析失败")
		return
	}

	// 2. 判断用户是否已经登录
	key := fmt.Sprint("user_", userId)
	value := tool.GetSession(ctx, key)
	if value == nil {
		tool.Failed(ctx, "用户未登录")
		return
	}

	var member model.Member
	s := bytes.NewReader([]byte(value.(string)))
	if err := json.NewDecoder(s).Decode(&member); err != nil {
		tool.Failed(ctx, "用户未登录")
		return
	}

	// 3. file 保存
	fileName := fmt.Sprintf("./uploads/%d-%s", time.Now().Unix(), fileHeader.Filename)
	if err := ctx.SaveUploadedFile(fileHeader, fileName); err != nil {
		tool.Failed(ctx, "文件保存失败")
		return
	}

	// 3.1 将文件上传到fdfs
	var url string
	fileId := tool.UploadFile(fileName)
	if fileId != "" {
		// 上传成功,删除本地文件
		os.Remove(fileName)
		url = tool.GetConfig().Fdfs.ServerUrl + fileId
	} else {
		// 上传失败,保留本地文件
		url = tool.GetConfig().ServerUrl + fileName[1:]
	}

	// 4. 保存路径到数据库
	ms := service.MemberService{}
	fileUrl := ms.UploadAvatar(member.Id, url)
	if fileUrl == "" {
		tool.Failed(ctx, "文件存储失败")
		return
	}
	tool.Success(ctx, url)
}

// nameLogin 用户名+密码+验证码 登录
func (mc *MemberController) nameLogin(ctx *gin.Context) {
	// 1 解析参数
	var loginParams param.LoginParam
	if err := ctx.ShouldBindJSON(&loginParams); err != nil {
		tool.Failed(ctx, "参数解析失败")
		return
	}

	// 2 验证验证码
	ok := tool.VerifyCaptcha(loginParams.Id, loginParams.Value)
	if !ok {
		tool.Failed(ctx, "验证码不正确, 请重新验证")
		return
	}

	// 3 登录
	ms := service.MemberService{}
	member := ms.Login(loginParams.Name, loginParams.Password)
	if member.Id != 0 {
		key := fmt.Sprintf("%s_%d", "user_", member.Id)
		s := strings.Builder{}
		encoder := json.NewEncoder(&s)
		if err := encoder.Encode(member); err != nil {
			tool.Failed(ctx, "参数序列化失败")
			return
		}
		if err := tool.SetSession(ctx, key, s); err != nil {
			tool.Failed(ctx, "登录失败")
			return
		}
		tool.Success(ctx, member)
		return
	}
	tool.Failed(ctx, "登录失败")
}

func (mc *MemberController) verifyCaptcha(ctx *gin.Context) {
	// 解析参数
	var captcha tool.CaptchaResult
	if err := ctx.ShouldBindJSON(&captcha); err != nil {
		tool.Failed(ctx, "参数解析失败")
		return
	}

	// 验证
	if ok := tool.VerifyCaptcha(captcha.Id, captcha.VerifyValue); !ok {
		tool.Failed(ctx, "验证码错误")
		return
	}
	tool.Success(ctx, nil)
}

func (mc *MemberController) captcha(ctx *gin.Context) {
	// 生成验证码
	captchaId, b64str, err := tool.GenerateCaptcha()
	if err != nil {
		log.Printf("generating captcha: %s\n", err.Error())
		tool.Failed(ctx, "生成验证码失败")
		return
	}
	tool.Success(ctx, &tool.CaptchaResult{
		Id:          captchaId,
		Base64Blob:  b64str,
		VerifyValue: "",
	})
}

func (mc *MemberController) sendSmsCode(ctx *gin.Context) {
	// 获取参数
	phone, ok := ctx.GetQuery("phone")
	if !ok {
		tool.Failed(ctx, "参数解析失败")
		return
	}

	// 发送验证码
	ms := service.MemberService{}
	isSend := ms.SendCode(phone)
	if isSend {
		tool.Success(ctx, nil)
		return
	}
	tool.Failed(ctx, "发送失败")
}

// smsLogin 手机号+短信登录
func (mc *MemberController) smsLogin(ctx *gin.Context) {
	var smsLoginParam param.SmsLoginParam
	if err := tool.Decode(ctx.Request.Body, &smsLoginParam); err != nil {
		tool.Failed(ctx, "参数解析失败")
		return
	}

	// 完成手机+验证码登录
	ms := service.MemberService{}
	member := ms.SmsLogin(smsLoginParam)
	if member != nil {
		// Success
		bts, err := json.Marshal(member)
		if err != nil {
			tool.Failed(ctx, "参数序列化失败")
			return
		}

		s := strings.Builder{}
		s.WriteString("user_")
		s.WriteString(strconv.FormatInt(member.Id, 10))
		if err := tool.SetSession(ctx, s.String(), string(bts)); err != nil {
			tool.Failed(ctx, "登录失败")
			return
		}

		// 设置cookie
		domain := tool.GetConfig().ServerUrl
		domain = strings.TrimLeft(strings.TrimLeft(domain, "http://"), "https://")
		ctx.SetCookie(tool.CookieName, strconv.Itoa(int(member.Id)), tool.CookieExpire, "/", domain, true, true)

		tool.Success(ctx, member)
		return
	}
	tool.Failed(ctx, "登录失败")
}
